//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<data_entry_cache.h>
///	@path	~/src/database/xres/
///	@date	2007/12/19
///	@desc	Data entry cache.

#pragma once

#include "xeres.h"

#include "lib/utilities/dict.h"
#include "lib/system/lock.h"

#include "database/IData.h"

namespace xeres {

	/*!
		\class	DataEntryCache
		\brief	Caches created data entry for frequently access.
	*/
	class DataEntryCache
	{
	public:

		/// \ctor
		DataEntryCache( size_t init_cache_size );

		/// \dtor
		~DataEntryCache( void );

	//@ interface

		/*!
			\brief		Set optimal cache slot size.
						Notice this operation will flush all cached nodes.
		*/
		void SetCacheSize( size_t lv1 , size_t lv2 );

		/*!
			\brief		Query cached data entry, return null indicate not cached.
		*/
		RefPass<IData> QueryCache( const WString& path );

		/*!
			\brief		Insert new cache in, & flush cache if needed.
						Notice this function will not examine if node exists in current cache.
						Caller must check it before insert. Debug version will check it for safety.
		*/
		void InsertCache( const WString& path , RefWeak<IData> data );

		/*!
			\brief		Flush cache.
		*/
		void FlushCache( void );

	private:

		// clear cache
		void ClearCache( void );

		// reset cache
		void ResetCache( size_t newSize );

		// cache node lv2
		struct _Lv2CacheNode
		{
			Time			m_stamp;
			Ref<IData>	m_entry;
		};

		// cache node lv1
		struct ALIGNED _Lv1CacheNode
		{
			Time			m_lastAccess;
			size_t			m_hash;
			_Lv1CacheNode * m_prev;
			_Lv1CacheNode *	m_next;
			Ref<IData> m_entry;
			WString			m_path;
		};

		/*!
			\desc

			All newly inserted node will be saved in lv2 cache, and make a time stamp.
			When we access it again soon, program will try to insert it in lv1 cache.
		*/

	//@ data

		ThreadLock						m_lock;

		size_t							m_lv1max;
		size_t							m_lv1size;

		size_t							m_lv2max;

		dict<WString,_Lv2CacheNode>		m_cache_lv2;

		_Lv1CacheNode *					m_cache_lv1;
		_Lv1CacheNode *					m_cache_lv1_free;

		_Lv1CacheNode *					m_cache_lv1_root;
		_Lv1CacheNode *					m_cache_lv1_end;

	};

} // namespace xeres
